﻿using BootstrapBlazor.Components;
using BPM.Web.Shared.Data;

namespace BPM.Web.Shared.Extensions;

/// <summary>
/// TreeItem组件扩展
/// </summary>
public static class TreeItemExtensions
{
    /// <summary>
    /// ITreeNode集合数据转换为TreeItem
    /// </summary>
    /// <typeparam name="TKey">标识类型</typeparam>
    /// <param name="items"></param>
    /// <returns></returns>
    public static List<TreeItem> BuildTree<Tsource, Tkey>(this IEnumerable<Tsource>? items, Action<Tsource, TreeItem> action)
        where Tsource : class, ITreeNode<Tsource, Tkey>
        where Tkey : struct
    {
        if (items == null)
        {
            return new();
        }

        var result = new List<TreeItem>();
        foreach (var item in items)
        {
            var node = new TreeItem();
            action(item, node);
            if (item.Children.Any())
            {
                node.Items = BuildTree<Tsource, Tkey>(item.Children, action);
            }
            result.Add(node);
        }
        return result;
    }

    /// <summary>
    /// 获得所有选中标识值
    /// </summary>
    /// <typeparam name="TKey">标识类型</typeparam>
    /// <param name="items"></param>
    /// <returns></returns>
    public static IEnumerable<TKey> GetCheckedKeys<TKey>(this IEnumerable<TreeItem>? items)
        where TKey : struct
    {
        if (items == null)
        {
            return Enumerable.Empty<TKey>();
        }

        var result = new List<TKey>();
        foreach (var item in items)
        {
            GetCheckedKeys(item, ref result);
        }
        return result;
    }

    /// <summary>
    /// 级联设置复选状态
    /// </summary>
    /// <typeparam name="TKey">标识类型</typeparam>
    /// <param name="items"></param>
    /// <param name="keys">选中标识值</param>
    public static void CascadeSetCheck<TKey>(this IEnumerable<TreeItem>? items, IEnumerable<TKey>? keys)
    {
        if (items != null && keys != null && keys.Any())
        {
            foreach (var item in items)
            {
                item.Checked = item.Key is TKey key && keys.Contains(key);
                CascadeSetCheck(item.Items, keys);
            }
        }
    }

    private static void GetCheckedKeys<TKey>(TreeItem item, ref List<TKey> keys) where TKey : struct
    {
        if (item.Checked && item.Key is TKey key)
        {
            keys.Add(key);
        }
        foreach (var child in item.Items)
        {
            GetCheckedKeys(child, ref keys);
        }
    }
}
